package spring;

import java.util.*;

final class PostProcessorRegistrationDelegate {

    private PostProcessorRegistrationDelegate() {

    }

    public static void invokeBeanFactoryPostProcessors(DefaultListableBeanFactory registry) {

        Set<String> processedBeans = new HashSet<>();

        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        ArrayList<String> postProcessorNames = registry.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class);

        // 首先执行实现了PriorityOrdered接口的,此处执行ConfigurationClassPostProcessor
        for (String postProcessorName : postProcessorNames) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(postProcessorName);
            Class clazz = beanDefinition.getClazz();
            if (PriorityOrdered.class.isAssignableFrom(clazz)) {
                processedBeans.add(postProcessorName);
                currentRegistryProcessors.add(registry.getBean(postProcessorName, BeanDefinitionRegistryPostProcessor.class));
            }
        }
        sortPostProcessors(currentRegistryProcessors, registry);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();

        // 然后执行Ordered接口的，实际上并没有执行
        postProcessorNames = registry.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class);
        for (String postProcessorName : postProcessorNames) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(postProcessorName);
            Class clazz = beanDefinition.getClazz();
            if (!processedBeans.contains(postProcessorName) && clazz.isAssignableFrom(Ordered.class)) {
                currentRegistryProcessors.add(registry.getBean(postProcessorName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(postProcessorName);
            }
        }
        sortPostProcessors(currentRegistryProcessors, registry);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();

        // 最后执行剩下的BeanDefinitionRegistryPostProcessor
        postProcessorNames = registry.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class);
        for (String postProcessorName : postProcessorNames) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(postProcessorName);
            Class clazz = beanDefinition.getClazz();
            if (!processedBeans.contains(postProcessorName)) {
                currentRegistryProcessors.add(registry.getBean(postProcessorName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(postProcessorName);
            }
        }
        sortPostProcessors(currentRegistryProcessors, registry);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();

        invokeBeanFactoryPostProcessors(regularPostProcessors, registry);
        invokeBeanFactoryPostProcessors(registryProcessors, registry);

    }

    private static void sortPostProcessors
            (List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors, DefaultListableBeanFactory registry) {
        //假装实现了排序
    }

    private static void invokeBeanDefinitionRegistryPostProcessors
            (List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors, DefaultListableBeanFactory registry) {
        for (BeanDefinitionRegistryPostProcessor currentRegistryProcessor : currentRegistryProcessors) {
            currentRegistryProcessor.postProcessBeanDefinitionRegistry(registry);
        }
        ArrayList<String> beanNamesForType = registry.getBeanNamesForType(ImportBeanDefinitionRegistrar.class);
        for (String s : beanNamesForType) {
            ImportBeanDefinitionRegistrar bean = registry.getBean(s, ImportBeanDefinitionRegistrar.class);
            bean.registerBeanDefinitions(registry);
        }

    }

    private static void invokeBeanFactoryPostProcessors(List<? extends BeanFactoryPostProcessor> processors, DefaultListableBeanFactory registry) {
        // 源码中此处主要用于@Configuration类的CGLIB代理，以对@Bean注解的其他注解进行解析，此处未实现@Bean。。。这里也就不写了，空实现
        for (BeanFactoryPostProcessor processor : processors) {
            processor.postProcessBeanFactory(registry);
        }
    }

    public static void registerBeanPostProcessors(DefaultListableBeanFactory registry) {

        // 此处和BeanFactoryBeanPostProcessor类似，也是PriorityOrdered接口等，然后挨个实现
        // 但是主要在这里有有两个内置的BeanPostProcessor，一个是 AutowiredAnnotationBeanPostProcessor，一个是 CommonAnnotationBeanPostProcessor
        // AutowiredAnnotationBeanPostProcessor 是@Autowired、@Value注入
        // CommonAnnotationBeanPostProcessor 是 @Resource 注入

        List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();


        ArrayList<String> postProcessorNames = registry.getBeanNamesForType(BeanPostProcessor.class);

        List<BeanPostProcessor> orderedPostProcessorNames = new ArrayList<>();

        List<BeanPostProcessor> nonOrderedPostProcessorNames = new ArrayList<>();

        for (String postProcessorName : postProcessorNames) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(postProcessorName);
            Class clazz = beanDefinition.getClazz();
            BeanPostProcessor pp = registry.getBean(postProcessorName, BeanPostProcessor.class);
            if (PriorityOrdered.class.isAssignableFrom(clazz)) {
                priorityOrderedPostProcessors.add(pp);
            } else if (Ordered.class.isAssignableFrom(clazz)) {
                orderedPostProcessorNames.add(pp);
            } else {
                nonOrderedPostProcessorNames.add(pp);
            }
        }
        for (BeanPostProcessor postProcessor : priorityOrderedPostProcessors) {
            registry.addBeanPostProcessor(postProcessor);
        }
        for (BeanPostProcessor postProcessor : orderedPostProcessorNames) {
            registry.addBeanPostProcessor(postProcessor);
        }
        for (BeanPostProcessor postProcessor : nonOrderedPostProcessorNames) {
            registry.addBeanPostProcessor(postProcessor);
        }


    }


}
